home *** CD-ROM | disk | FTP | other *** search
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is OEone Calendar Code, released October 31st, 2001.
- *
- * The Initial Developer of the Original Code is
- * OEone Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Garth Smedley <garths@oeone.com>
- * Mike Potter <mikep@oeone.com>
- * Chris Charabaruk <coldacid@meldstar.com>
- * Colin Phillips <colinp@oeone.com>
- * Karl Guertin <grayrest@grayrest.com>
- * Mike Norton <xor@ivwnet.com>
- * ArentJan Banck <ajbanck@planet.nl>
- * Eric Belhaire <belhaire@ief.u-psud.fr>
- * Philipp Kewisch <mozilla@kewis.ch>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- /**
- * Code which generates event and task (todo) preview tooltips/titletips
- * when the mouse hovers over either the event list, the task list, or
- * an event or task box in one of the grid views.
- *
- * (Portions of this code were previously in calendar.js and unifinder.js,
- * some of it duplicated.)
- */
-
- /** PUBLIC
- *
- * This changes the mouseover preview based on the start and end dates
- * of an occurrence of a (one-time or recurring) calEvent or calToDo.
- * Used by all grid views.
- */
-
- function onMouseOverItem( occurrenceBoxMouseEvent )
- {
- if ("occurrence" in occurrenceBoxMouseEvent.currentTarget) {
- // occurrence of repeating event or todo
- var occurrence = occurrenceBoxMouseEvent.currentTarget.occurrence;
-
- const toolTip = document.getElementById("itemTooltip");
-
- var holderBox;
- if (isEvent(occurrence)) {
- holderBox = getPreviewForEvent(occurrence, occurrence.startDate, occurrence.endDate);
- } else if (isToDo(occurrence)) {
- holderBox = getPreviewForTask(occurrence);
- }
- if (holderBox) {
- setToolTipContent(toolTip, holderBox);
- return true;
- }
- }
- return false;
- }
-
- /** For all instances of an event, as displayed by unifinder. **/
- function onMouseOverEventTree( toolTip, mouseEvent )
- {
- var item = unifinderTreeView.getItemFromEvent(mouseEvent);
- if (isEvent(item)) {
- var holderBox = getPreviewForEvent(item);
- if (holderBox) {
- setToolTipContent(toolTip, holderBox);
- return true;
- }
- }
- return false;
- }
-
- /** For all instances of a task, as displayed by unifinderToDo. **/
- function onMouseOverTaskTree( toolTip, mouseEvent )
- {
- var item = getToDoFromEvent( mouseEvent );
- if (isToDo(item)) {
- var holderBox = getPreviewForTask(item);
- if (holderBox) {
- setToolTipContent(toolTip, holderBox);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Removes old content from tooltip, adds new content box to tooltip,
- * then resizes the tooltip to the size of the new content box.
- *
- * @param tooltip The tooltip to modify.
- * @param holderBox The box element containing the new content.
- */
- function setToolTipContent(toolTip, holderBox)
- {
- while (toolTip.hasChildNodes()) {
- toolTip.removeChild( toolTip.firstChild );
- }
-
- // workaround bug 369225 (aspect: tooltip may not shrink height)
- toolTip.sizeTo(0, 0);
-
- toolTip.appendChild( holderBox );
- var width = holderBox.boxObject.width;
- var height = holderBox.boxObject.height;
-
- // workaround bug 369225 (aspect: tooltip height too short)
- // Add top and bottom border and padding to workaround bug where bottom
- // tooltip border disappears if wrapped description below header grid.
- height += 1 + 2 + 2 + 1;
-
- toolTip.sizeTo(width, height);
- }
-
- /**
- * Called when a user hovers over a todo element and the text for the mouse over is changed.
- */
-
- function getPreviewForTask( toDoItem )
- {
- if( toDoItem )
- {
- const vbox = document.createElement( "vbox" );
- vbox.setAttribute("class", "tooltipBox");
- // tooltip appears above or below pointer, so may have as little as
- // one half the screen height available (avoid top going off screen).
- vbox.maxHeight = Math.floor(screen.height / 2);
- boxInitializeHeaderGrid(vbox);
-
- var hasHeader = false;
-
- if (toDoItem.title)
- {
- boxAppendLabeledText(vbox, "tooltipTitle", toDoItem.title);
- hasHeader = true;
- }
-
- var location = toDoItem.getProperty("LOCATION");
- if (location)
- {
- boxAppendLabeledText(vbox, "tooltipLocation", location);
- hasHeader = true;
- }
-
- if (toDoItem.entryDate && toDoItem.entryDate.isValid)
- {
- boxAppendLabeledDateTime(vbox, "tooltipStart", toDoItem.entryDate);
- hasHeader = true;
- }
-
- if (toDoItem.dueDate && toDoItem.dueDate.isValid)
- {
- boxAppendLabeledDateTime(vbox, "tooltipDue", toDoItem.dueDate);
- hasHeader = true;
- }
-
- if (toDoItem.priority && toDoItem.priority != 0)
- {
- var priorityInteger = parseInt(toDoItem.priority);
- var priorityString;
-
- // These cut-offs should match calendar-event-dialog.js
- if (priorityInteger >= 1 && priorityInteger <= 4) {
- priorityString = calGetString('calendar', 'highPriority'); // high priority
- } else if (priorityInteger == 5) {
- priorityString = calGetString('calendar', 'mediumPriority'); // medium priority
- } else {
- priorityString = calGetString('calendar', 'lowPriority'); // low priority
- }
- boxAppendLabeledText(vbox, "tooltipPriority", priorityString);
- hasHeader = true;
- }
-
- if (toDoItem.status && toDoItem.status != "NONE")
- {
- var status = getToDoStatusString(toDoItem);
- boxAppendLabeledText(vbox, "tooltipStatus", status);
- hasHeader = true;
- }
-
- if (toDoItem.percentComplete != 0 && toDoItem.percentComplete != 100)
- {
- boxAppendLabeledText(vbox, "tooltipPercent", String(toDoItem.percentComplete)+"%");
- hasHeader = true;
- } else if (toDoItem.percentComplete == 100)
- {
- if (toDoItem.completedDate == null) {
- boxAppendLabeledText(vbox, "tooltipPercent", "100%");
- } else {
- boxAppendLabeledDateTime(vbox, "tooltipCompleted", toDoItem.completedDate);
- }
- hasHeader = true;
- }
-
- var description = toDoItem.getProperty("DESCRIPTION");
- if (description)
- {
- // display wrapped description lines like body of message below headers
- if (hasHeader) {
- boxAppendBodySeparator(vbox);
- }
- boxAppendBody(vbox, description);
- }
-
- return ( vbox );
- }
- else
- {
- return null;
- }
- }
-
- /**
- * Called when mouse moves over a different, or
- * when mouse moves over event in event list.
- * The instStartDate is date of instance displayed at event box
- * (recurring or multiday events may be displayed by more than one event box
- * for different days), or null if should compute next instance from now.
- */
- function getPreviewForEvent( event, instStartDate, instEndDate )
- {
- const vbox = document.createElement( "vbox" );
- vbox.setAttribute("class", "tooltipBox");
- // tooltip appears above or below pointer, so may have as little as
- // one half the screen height available (avoid top going off screen).
- vbox.maxHeight = Math.floor(screen.height / 2);
- boxInitializeHeaderGrid(vbox);
-
- if (event)
- {
- if (event.title)
- {
- boxAppendLabeledText(vbox, "tooltipTitle", event.title);
- }
-
- var location = event.getProperty("LOCATION");
- if (location)
- {
- boxAppendLabeledText(vbox, "tooltipLocation", location);
- }
-
- if (event.startDate || instStartDate)
- {
- var startDate, endDate;
- if (instStartDate && instEndDate) {
- startDate = instStartDate;
- endDate = instEndDate;
- } else {
- // Event may be recurrent event. If no displayed instance specified,
- // use next instance, or previous instance if no next instance.
- var occ = getCurrentNextOrPreviousRecurrence(event);
- startDate = instStartDate || occ.startDate;
- endDate = occ.endDate;
- }
- boxAppendLabeledDateTimeInterval(vbox, "tooltipDate", startDate, endDate);
- }
-
- if (event.status && event.status != "NONE")
- {
- var statusString = getEventStatusString(event);
- boxAppendLabeledText(vbox, "tooltipStatus", statusString);
- }
-
- var description = event.getProperty("DESCRIPTION");
- if (description)
- {
- boxAppendBodySeparator(vbox);
- // display wrapped description lines, like body of message below headers
- boxAppendBody(vbox, description);
- }
-
- return ( vbox );
- }
- else
- {
- return null;
- }
- }
-
-
- /** String for event status: (none), Tentative, Confirmed, or Cancelled **/
- function getEventStatusString(calendarEvent)
- {
- switch( calendarEvent.status )
- {
- // Event status value keywords are specified in RFC2445sec4.8.1.11
- case "TENTATIVE":
- return calGetString('calendar', "statusTentative");
- case "CONFIRMED":
- return calGetString('calendar', "statusConfirmed");
- case "CANCELLED":
- return calGetString('calendar', "statusCancelled");
- default:
- return "";
- }
- }
-
- /** String for todo status: (none), NeedsAction, InProcess, Cancelled, or Completed **/
- function getToDoStatusString(iCalToDo)
- {
- switch( iCalToDo.status )
- {
- // Todo status keywords are specified in RFC2445sec4.8.1.11
- case "NEEDS-ACTION":
- return calGetString('calendar', "statusNeedsAction");
- case "IN-PROCESS":
- return calGetString('calendar', "statusInProcess");
- case "CANCELLED":
- return calGetString('calendar', "statusCancelled");
- case "COMPLETED":
- return calGetString('calendar', "statusCompleted");
- default:
- return "";
- }
- }
-
- /**
- * PRIVATE: Append a separator, a thin space between header and body.
- *
- * @param vbox box to which to append separator.
- */
- function boxAppendBodySeparator(vbox) {
- const separator = document.createElement("separator");
- separator.setAttribute("class", "tooltipBodySeparator");
- vbox.appendChild(separator);
- }
-
- /**
- * PRIVATE: Append description to box for body text. Text may contain
- * paragraphs; line indent and line breaks will be preserved by CSS.
- * @param box box to which to append body
- * @param textString text of body
- */
- function boxAppendBody(box, textString)
- {
- var textNode = document.createTextNode(textString);
- var xulDescription = document.createElement("description");
- xulDescription.setAttribute("class", "tooltipBody");
- xulDescription.appendChild(textNode);
- box.appendChild(xulDescription);
- }
-
- /**
- * PRIVATE: Use dateFormatter to format date and time,
- * and to header grid append a row containing localized Label: date.
- */
- function boxAppendLabeledDateTime(box, labelProperty, date)
- {
- var dateFormatter = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
- .getService(Components.interfaces.calIDateTimeFormatter);
- date = date.getInTimezone(calendarDefaultTimezone());
- var formattedDateTime = dateFormatter.formatDateTime(date);
- boxAppendLabeledText(box, labelProperty, formattedDateTime);
- }
-
- /**
- * PRIVATE: Use dateFormatter to format date and time interval,
- * and to header grid append a row containing localized Label: interval.
- * @param box contains header grid.
- * @param labelProperty name of property for localized field label.
- * @param start calDateTime of start of time interval.
- * @param end calDateTime of end of time interval.
- */
- function boxAppendLabeledDateTimeInterval(box, labelProperty, start, end)
- {
- var dateFormatter = Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
- .getService(Components.interfaces.calIDateTimeFormatter);
- var startString = new Object();
- var endString = new Object();
- start = start.getInTimezone(calendarDefaultTimezone());
- end = end.getInTimezone(calendarDefaultTimezone());
- dateFormatter.formatInterval(start, end, startString, endString);
- if (endString.value != "") {
- boxAppendLabeledText(box, labelProperty, startString.value + ' - ' + endString.value);
- } else {
- boxAppendLabeledText(box, labelProperty, startString.value);
- }
- }
-
- /**
- * PRIVATE: create empty 2-column grid for header fields,
- * and append it to box.
- */
- function boxInitializeHeaderGrid(box)
- {
- var grid = document.createElement("grid");
- grid.setAttribute("class", "tooltipHeaderGrid");
- var rows;
- {
- var columns = document.createElement("columns");
- {
- var labelColumn = document.createElement("column");
- labelColumn.setAttribute("class", "tooltipLabelColumn");
- columns.appendChild(labelColumn);
- var valueColumn = document.createElement("column");
- valueColumn.setAttribute("class", "tooltipValueColumn");
- columns.appendChild(valueColumn);
- }
- grid.appendChild(columns);
- rows = document.createElement("rows");
- grid.appendChild(rows);
- }
- box.appendChild(grid);
- }
-
- /**
- * PRIVATE: To headers grid, append a row containing Label: value,
- * where label is localized text for labelProperty.
- * @param box box containing headers grid
- * @param labelProperty name of property for localized name of header
- * @param textString value of header field.
- */
- function boxAppendLabeledText(box, labelProperty, textString)
- {
- var labelText = calGetString('calendar', labelProperty);
- var rows = box.getElementsByTagName("rows")[0];
- {
- var row = document.createElement("row");
- {
- row.appendChild(createTooltipHeaderLabel(labelText));
- row.appendChild(createTooltipHeaderDescription(textString));
- }
- rows.appendChild(row);
- }
- }
-
- /** PRIVATE: create element for field label (for header grid). **/
- function createTooltipHeaderLabel(text)
- {
- var label = document.createElement("label");
- label.setAttribute("class", "tooltipHeaderLabel");
- label.appendChild(document.createTextNode(text));
- return label;
- }
-
- /** PRIVATE: create element for field value (for header grid). **/
- function createTooltipHeaderDescription(text)
- {
- var label = document.createElement("description");
- label.setAttribute("class", "tooltipHeaderDescription");
- label.appendChild(document.createTextNode(text));
- return label;
- }
-
- /**
- * If now is during an occurrence, return the occurrence.
- * Else if now is before an occurrence, return the next occurrence.
- * Otherwise return the previous occurrence.
- */
- function getCurrentNextOrPreviousRecurrence(calendarEvent)
- {
- if (!calendarEvent.recurrenceInfo) {
- return calendarEvent;
- }
-
- var dur = calendarEvent.duration.clone();
- dur.isNegative = true;
-
- // To find current event when now is during event, look for occurrence
- // starting duration ago.
- var probeTime = now();
- probeTime.addDuration(dur);
-
- var occ = calendarEvent.recurrenceInfo.getNextOccurrence(probeTime);
-
- if (!occ) {
- var occs = calendarEvent.recurrenceInfo.getOccurrences(calendarEvent.startDate, probeTime, 0, {});
- occ = occs[occs.length -1];
- }
- return occ;
- }
-